#include "Ecran.h"
#include <math.h>

Ecran::Ecran()
{
	SDL_Init(SDL_INIT_VIDEO);
	_surface = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE | SDL_DOUBLEBUF );
	_origine = Point();
}

Ecran::Ecran(const int & largeur, const int & hauteur)
{
	SDL_Init(SDL_INIT_VIDEO);
	_surface = SDL_SetVideoMode(largeur, hauteur, 32, SDL_HWSURFACE | SDL_DOUBLEBUF );
	_origine = Point();
}

Ecran::Ecran(const int & largeur, const int & hauteur, const string & titre)
{
	SDL_Init(SDL_INIT_VIDEO);
	_surface = SDL_SetVideoMode(largeur, hauteur, 32, SDL_HWSURFACE | SDL_DOUBLEBUF );
	SDL_WM_SetCaption(titre.c_str(), NULL);
	_origine = Point();
}

Ecran::~Ecran()
{
	SDL_Quit();
}

void Ecran::maj()
{
	SDL_Flip(_surface);
}

bool Ecran::controlPoint(Point p)
{
    if( (p.x >= 0) && (p.y>=0) && (p.x < _surface->w) && (p.y < _surface->h) )
        return true;
    else
        return false;
}

void Ecran::setOrigine(Point p)
{
    if( controlPoint(p) )
        _origine = p;
}

void Ecran::drawRepere()
{
    drawLine(Point(0, -getHauteur()),Point(0,getHauteur()));
    drawLine(Point(-getLargeur(),0),Point(getLargeur(),0));
}

Point Ecran::getOrigine()
{
    return _origine;
}

int Ecran::getHauteur()
{
    return _surface->h;
}

int Ecran::getLargeur()
{
    return _surface->w;
}

void Ecran::setCouleurFond(const Uint32 & couleur)
{
	SDL_FillRect(_surface, NULL, couleur);
	maj();
}

Uint32 Ecran::getCouleur(const unsigned char & r,const unsigned char & g,const unsigned char & b)
{
	return SDL_MapRGB(_surface->format, r,g,b);
}

void Ecran::saveBMP(string chemin)
{
	SDL_SaveBMP(_surface,chemin.c_str());
}

void Ecran::drawPoint(Point pt, Uint32 couleur, bool mj)
{
    if(!couleur)
    {
        couleur = getCouleur(0,0,0);
    }

    Point ptATracer;

    if(_origine != Point(0,0))
    {
        ptATracer.x = _origine.x + pt.x;
        ptATracer.y = _origine.y - pt.y;
    }
    else
    {
        ptATracer = pt;
    }

    if(controlPoint(ptATracer))
    {
        SDL_LockSurface(_surface);
        int bpp = _surface->format->BytesPerPixel;

        Uint8 *p = (Uint8 *)_surface->pixels + ptATracer.y * _surface->pitch + ptATracer.x * bpp;

        switch(bpp) {
            case 1:
                *p = couleur;
                break;

            case 2:
                *(Uint16 *)p = couleur;
                break;

            case 3:
                if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
                    p[0] = (couleur >> 16) & 0xff;
                    p[1] = (couleur >> 8) & 0xff;
                    p[2] = couleur & 0xff;
                } else {
                    p[0] = couleur & 0xff;
                    p[1] = (couleur >> 8) & 0xff;
                    p[2] = (couleur >> 16) & 0xff;
                }
                break;

            case 4:
                *(Uint32 *)p = couleur;
                break;
	}

	if(mj)
		maj();

	SDL_UnlockSurface(_surface);
    }

}

void Ecran::drawLine(Point p1,Point p2, Uint32 couleur, bool mj) //Algo de Bresenham
{
    if(!couleur)
        couleur = getCouleur(0,0,0);

    int x1 = p1.x , y1 = p1.y , x2 =  p2.x , y2 = p2.y ;
	int distanceX = abs(x2 - x1);
	int distanceY = abs(y2 - y1);

	int sx,sy;

	if(x1 < x2)
		sx = 1;
	else
		sx = -1;

	if(y1 < y2)
		sy = 1;
	else
		sy = -1;

	int err = distanceX - distanceY;
	int e2;

	while( x1!=x2 || y1!=y2)
	{
		drawPoint(Point(x1,y1),couleur,false);
		e2 = 2*err;

		if(e2 > -distanceY)
		{
			err -= distanceY;
			x1 += sx;
		}
		if(e2 < distanceX)
		{
			err += distanceX;
			y1 += sy;
		}
	}

	maj();
}

void Ecran::drawVecteur(Vecteur v, Uint32 couleur)
{
    drawLine(Point(0,0),Point(v.x,v.y),couleur);
}

void Ecran::drawVecteur(Point p, Vecteur v, Uint32 couleur)
{
    drawLine(p,Point(p.x + v.x,p.y + v.y),couleur);
}

void Ecran::drawVecteurs(Courbe c, Uint32 couleur)
{
    for(int i = 0 ; i < (c.getDegre() + 1 ) ; i++)
        drawLine( Point() , Point( (int)c.getVecteur()[i].x , (int)c.getVecteur()[i].y ), couleur);
}

void Ecran::drawTrace(Courbe c, Uint32 couleur)
{
    Vecteur * v = c.getVecteur();

    for(int i = 0; i < c.getDegre(); i++)
      drawLine(Point(v[i].x,v[i].y),Point(v[i+1].x,v[i+1].y),couleur);
}

void Ecran::drawCourbe(Courbe c,unsigned int nbP , Uint32 couleur )
{
    Point * tab = new Point[nbP];
    tab = c.getEnsPt(nbP);

    for(unsigned int i = 0; i < nbP; i++)
      drawLine(tab[i],tab[i+1],couleur);

    delete[] tab;
}

void Ecran::drawBiggerPixel(Point p ,unsigned int size ,Uint32 couleur)
{

    size--;
    unsigned int x = p.x -size , y = p.y - size;

    if(!couleur) couleur = getCouleur(0,0,255);

    drawPoint(p,couleur,false);

    while(!(y == (p.y + size + 1)))
    {
        drawPoint(Point(x,y),couleur,false);
        y++;
    }

    x = p.x + size; y = p.y - size;

    while(!(y == (p.y + size + 1)))
    {
        drawPoint(Point(x,y),couleur,false);
        y++;
    }

    x = p.x -size ; y = p.y - size;

    while(!(x == (p.x + size + 1)))
    {
        drawPoint(Point(x,y),couleur,false);
        x++;
    }

    x = p.x - size ; y = p.y + size;

    while(!(x == (p.x + size + 1)))
    {
        drawPoint(Point(x,y),couleur,false);
        x++;
    }
    maj();
}
